package com.mmall.filter;

import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import com.mmall.common.ApplicationContextHelper;
import com.mmall.common.JsonData;
import com.mmall.common.RequestHolder;
import com.mmall.model.SysUser;

import com.mmall.service.SysCoreService;
import com.mmall.util.JsonMapper;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;

/**
 * 权限控制拦截器
 */
@Slf4j
public class AclControlFilter implements Filter {
    /**
     * 全局的要过滤掉的url的set
     */
    private static Set<String> exclusionUrlSet = new ConcurrentSkipListSet<>();

    /**
     * 没有权限访问的跳转页面
     */
    private final static String noAuthUrl = "/sys/user/noAuth.page";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        String exclusionUrls = filterConfig.getInitParameter("exclusionUrls");//exclusionUrls是配置文件里指定的字段，配置多个白名单url
        List<String> exclusionUrlList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(exclusionUrls);
        exclusionUrlSet = Sets.newConcurrentHashSet(exclusionUrlList);

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String servletPath = request.getServletPath();//获取到的路径

        Map requMap = request.getParameterMap();

        if (exclusionUrlSet.contains(servletPath)){
            //如果存在于白名单内
            filterChain.doFilter(request,response);
            return;
        }
        //取出当前登录用户
        SysUser sysUser = RequestHolder.getCurrentUser();
        if (sysUser == null){
            log.info("对于要访问的路径：{}，需要有登录用户才可以，包含参数信息：{}",servletPath, JsonMapper.objToString(requMap));
            //没有权限不进行操作
            noAuth(request,response);
            return;
        }
        //该filter并不是spring管理的，所以必须使用ApplicationContextHelper工具进行转换为bean
        SysCoreService sysCoreService = ApplicationContextHelper.popBean(SysCoreService.class);

        if (!sysCoreService.hasUrlAcl(servletPath)){
            //判断是否有权限访问
            log.info("{}--访问--{}，需要有登录用户才可以，包含参数信息：{}",JsonMapper.objToString(sysUser.getUsername()),servletPath, JsonMapper.objToString(requMap));
            noAuth(request,response);
            return;
        }
        filterChain.doFilter(servletRequest,servletResponse);

        return;

    }

    /**
     * 无权限访问的操作
     * @param request
     * @param response
     */
    private void noAuth(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String servletPath = request.getServletPath();
        if (servletPath.endsWith(".json")) {
            JsonData jsonData = JsonData.fail("没有访问权限，如需要访问，请联系管理员");
            response.setHeader("Content-Type", "application/json");
            response.getWriter().print(JsonMapper.objToString(jsonData));
            return;
        } else {
            clientRedirect(noAuthUrl, response);
            return;
        }
    }

    private void clientRedirect(String url, HttpServletResponse response) throws IOException{
        response.setHeader("Content-Type", "text/html");
        response.getWriter().print("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
                + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" + "<head>\n" + "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"/>\n"
                + "<title>跳转中...</title>\n" + "</head>\n" + "<body>\n" + "跳转中，请稍候...\n" + "<script type=\"text/javascript\">//<![CDATA[\n"
                + "window.location.href='" + url + "?ret='+encodeURIComponent(window.location.href);\n" + "//]]></script>\n" + "</body>\n" + "</html>\n");
    }

    @Override
    public void destroy() {

    }
}
